package org.bing.engine.console.service;

import java.util.Date;
import java.util.List;

import org.bing.engine.console.remote.RemoteFactory;
import org.bing.engine.core.domain.Application;
import org.bing.engine.core.domain.ApplicationOfDomain;
import org.bing.engine.core.domain.ContainerInstance;
import org.bing.engine.core.domain.ContainerSetting;
import org.bing.engine.core.domain.Controller;
import org.bing.engine.core.domain.Domain;
import org.bing.engine.core.service.ContainerLifecycle;

@SuppressWarnings("unchecked")
public class ContainerInstanceManager extends AbstractHibernateManager {
    private ApplicationOfDomainManager appOfDomainManager;
    private RemoteFactory remoteFactory;

    public void setRemoteFactory(RemoteFactory factory) {
        this.remoteFactory = factory;
    }

    public void setApplicationOfDomainManager(ApplicationOfDomainManager mgr) {
        this.appOfDomainManager = mgr;
    }

    public ContainerLifecycle getContainerLifecycle(Controller c) {
        return remoteFactory.getRemoteService(c, ContainerLifecycle.class);
    }

    public void save(ContainerInstance instance) {
        template.saveOrUpdate(instance);
    }

    public ContainerInstance findByGlobalId(String globalId) {
        String hql = "select t from ContainerInstance t where t.globalId=?";
        return (ContainerInstance) super.findUniqueObject(hql, new Object[] { globalId });
    }

    public List<ContainerInstance> findByDomainAndApplication(Domain dom, Application app) {
        if (dom == null && app == null) {
            String hql = "select t from ContainerInstance t";
            return template.find(hql);
        } else if (dom == null) {
            String hql = "select t from ContainerInstance t where t.application=?";
            return template.find(hql, app);
        } else if (app == null) {
            String hql = "select t from ContainerInstance t where domain=?";
            return template.find(hql, dom);
        }
        String hql = "select t from ContainerInstance t where t.domain=? and t.application=?";
        return (List<ContainerInstance>) template.find(hql, new Object[] { dom, app });
    }

    public ContainerInstance startNew(Controller controller, Domain domain, Application app) {
        ApplicationOfDomain appOfDomain = appOfDomainManager.findByDomainAndApplication(domain, app);
        if (appOfDomain == null) {
            throw new RuntimeException("Can't find container setting for " + domain.getName() + ":" + app.getName());
        }
        ContainerSetting setting = appOfDomain.getSetting();
        // startup container, deploy app
        ContainerLifecycle lifecycle = getContainerLifecycle(controller);
        ContainerInstance inst = lifecycle.startup(setting, app);
        // save container instance info
        inst.setDomain(domain);
        inst.setApplication(app);
        inst.setController(controller);
        inst.setStartTime(new Date());
        inst.setLastActivityTime(new Date());
        template.saveOrUpdate(inst);
        return inst;
    }

    public void shutdown(ContainerInstance instance) {
        Controller controller = instance.getController();
        ContainerLifecycle lifecycle = getContainerLifecycle(controller);
        lifecycle.shutdown(instance);
        template.delete(instance);
    }

    public void destory(ContainerInstance instance) {
        try {
            shutdown(instance);
        } catch (Exception e) {
            logger.error("Fail to shutdown " + instance, e);
        }
        template.delete(instance);
    }
}
